﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace OtomatSearching.Engine
{
    public static class BalanHelper
    {
        public const string TOKEN = "?!";

        public static int GetPriority(string ip_str_input)
        {
            //if (ip_str_input == "-")
            //    return 2;
            //if (ip_str_input == "+")
            //    return 1;
            //// ip_str_input = "|" hoac "%";
            return 0;
        }

        public static void Normalize(ref string ip_str_expression)
        {
            var v_str_pattern = @"(\s+)";
            ip_str_expression = Regex.Replace(ip_str_expression.Trim(), v_str_pattern, " ");
            ip_str_expression = Regex.Replace(ip_str_expression, @"\s*?(\+|\-|\%|\(|\)|\|)\s{0,}", match =>
                string.Format("{0}{1}{0}", TOKEN, match.Value.Trim())
                );
        }

        public static bool IsOperator(string ip_str_input)
        {
            return Regex.Match(ip_str_input, @"\+|\-|\%|\(|\)|\|").Success;
        }

        public static bool IsOperand(string ip_str_input)
        {
            return IsOperator(ip_str_input) == false;
        }

        public static string[] Infix2Postfix(string ip_str_input, out string[] op_str_patterns)
        {
            if (string.IsNullOrEmpty(ip_str_input) == true)
            {
                throw new ArgumentNullException("ip_str_input", "Input is null");

            }
            Normalize(ref ip_str_input);
            var stack = new Stack<string>();
            var lpostfix = new List<string>();
            var lpattern = new List<string>();

            var tokens = ip_str_input.Split(new string[] { TOKEN }, StringSplitOptions.RemoveEmptyEntries);

            for (int i = 0; i < tokens.Length; i++)
            {
                var s = tokens[i];
                if (IsOperand(s) == true)
                {
                    lpostfix.Add(s);
                    lpattern.Add(s);
                }
                else if (s == "(")
                {
                    stack.Push(s);
                }
                else if (s == ")")
                {
                    var x = stack.Pop();
                    while (x != "(" && stack.Count > 0)
                    {
                        lpostfix.Add(x);
                        x = stack.Pop();
                    }
                }
                else // IsOperator(s)
                {
                    //while (stack.Count > 0 && GetPriority(s) <= GetPriority(stack.Peek()))
                    //{
                    //    lpostfix.Add(stack.Pop());
                    //}
                    stack.Push(s);
                }
            }

            while (stack.Count > 0)
            {
                lpostfix.Add(stack.Pop());
            }

            op_str_patterns = lpattern.ToArray();
            return lpostfix.ToArray();
        }

        public static string Infix2Postfix(string ip_str_input)
        {
            if (string.IsNullOrEmpty(ip_str_input) == true)
            {
                throw new ArgumentNullException("ip_str_input", "Input is null");

            }
            Normalize(ref ip_str_input);
            var stack = new Stack<string>();
            var postfix = new StringBuilder();
            var tokens = ip_str_input.Split(new string[] { TOKEN }, StringSplitOptions.RemoveEmptyEntries);

            for (int i = 0; i < tokens.Length; i++)
            {
                var s = tokens[i];
                if (IsOperand(s) == true)
                {
                    postfix.Append(s).Append(TOKEN);
                }
                else if (s == "(")
                {
                    stack.Push(s);
                }
                else if (s == "(")
                {
                    var x = stack.Pop();
                    while (x != "(" && stack.Count > 0)
                    {
                        postfix.Append(x).Append(TOKEN);
                        x = stack.Pop();
                    }
                }
                else // IsOperator(s)
                {
                    while (stack.Count > 0 && GetPriority(s) <= GetPriority(stack.Peek()))
                    {
                        postfix.Append(stack.Pop()).Append(TOKEN);
                    }
                    stack.Push(s);
                }
            }

            while (stack.Count > 0)
            {
                postfix.Append(stack.Pop()).Append(TOKEN);
            }

            return postfix.ToString();
        }
    }
}
